package com.jjb.saas.gen.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jjb.saas.gen.constants.CustomException;
import com.jjb.saas.gen.constants.GenConstants;
import com.jjb.saas.gen.controller.PdmanJsonCmd;
import com.jjb.saas.gen.entity.GenTable;
import com.jjb.saas.gen.entity.GenTableColumn;
import com.jjb.saas.gen.mapper.GenTableColumnMapper;
import com.jjb.saas.gen.mapper.GenTableMapper;
import com.jjb.saas.gen.service.GenTabelServiceI;
import com.jjb.saas.gen.service.executor.GenPdmanExe;
import com.jjb.saas.gen.utils.*;
import lombok.RequiredArgsConstructor;
import org.apache.commons.io.FileUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author: WGG
 * @Date: 2022/3/26 15:36
 */
@Service
@RequiredArgsConstructor
public class GenTableServiceImpl extends ServiceImpl<GenTableMapper, GenTable> implements GenTabelServiceI {

    private final GenPdmanExe genPdmanExe;
    private final GenTableColumnMapper genTableColumnMapper;
    @Override
    public List<GenTable> selectDbTableListByNames(String[] tableNames) {
        return baseMapper.selectDbTableListByNames(tableNames);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveGenTableInfo(String[] tableNames) {
        List<GenTable> genTables = baseMapper.selectDbTableListByNames(tableNames);
        this.importGenTable(genTables);
        return false;
    }

    @Override
    public synchronized void generatorCode(String tableName) {
        // 查询表信息
        GenTable table = baseMapper.selectGenTableByName(tableName);
        // 设置主子表信息
        //setSubTable(table);
        // 设置主键列信息
        setPkColumn(table);
        setEnums(table);
        VelocityInitializer.initVelocity();

        VelocityContext context = VelocityUtils.prepareContext(table);

        // 获取模板列表
        List<String> templates = VelocityUtils.getTemplateList(table,table.getTplCategory());
        for (String template : templates)
        {
            if (!StringUtils.containsAny(template, "sql.vm", "api.js.vm", "index.vue.vm", "index-tree.vue.vm"))
            {
                mergeTem(template,context,table);
            }
        }
        //是否有枚举的存在
        if(table.isHasEnum()){
            String enumTem = "vm/java/enums/enum.java.vm";
            for (GenTableColumn column : table.getColumns()) {
                if(column.isEnumFun()){

                    table.setEnumClassName(column.getEnumClassName());
                    table.setEnumDictTypeName(column.getEnumTypeName());
                    VelocityUtils.addPrepareContext(column,context);
                    mergeTem(enumTem,context,table);
                }
            }
        }
    }

    @Override
    public String generatorPdm(PdmanJsonCmd pdmanJsonCmd) {
        return genPdmanExe.execute(pdmanJsonCmd);
    }

    /**
     * 渲染模板
     * @param template
     * @param context
     * @param table
     */
    public void mergeTem(String template,VelocityContext context,GenTable table){
        // 渲染模板
        StringWriter sw = new StringWriter();
        Template tpl = Velocity.getTemplate(template, "UTF-8");
        tpl.merge(context, sw);
        try
        {
            String path = getGenPath(table, template);
            FileUtils.writeStringToFile(new File(path), sw.toString(), "UTF-8");
        }
        catch (IOException e)
        {
            e.printStackTrace();
            throw new CustomException(template+"渲染模板失败，表名：" + table.getTableName());
        }
    }
    /**
     * 获取代码生成地址
     *
     * @param table 业务表信息
     * @param template 模板文件路径
     * @return 生成地址
     */
    public static String getGenPath(GenTable table, String template)
    {
        String genPath = table.getGenPath();
        if (StringUtils.equals(genPath, "/"))
        {
            return System.getProperty("user.dir") + File.separator + "src" + File.separator + VelocityUtils.getFileName(template, table);
        }
        return genPath + File.separator + VelocityUtils.getFileName(template, table);
    }


    /**
     * 设置枚举信息 table
     * @param table
     */
    public void setEnums(GenTable table){
        for (GenTableColumn column : table.getColumns()){
            if(column.isBooleanEnumFun()){
                table.setHasBooleanEnum("1");
            }
            if(column.isEnumFun()){

                if(ObjectUtil.isNotEmpty(column.getEnumInfo())){
                    JSONObject json = JSON.parseObject(column.getEnumInfo());
                    Object className = json.get("class");
                    Object typeName = json.get("type");
                    Object classInfo = json.get("info");

                    if(ObjectUtil.isNotEmpty(className)){
                        //获取类名
                        String classNameStr = className.toString();
                        //保存枚举类型到数据类型表,待做
                        JSONArray enumDatas = json.getJSONArray("data");
                        if(ObjectUtil.isNotEmpty(enumDatas)){
                            column.setEnumClassName(classNameStr);
                            column.setEnumTypeName(ObjectUtil.isNotEmpty(typeName)?typeName.toString():null);
                            column.setEnumClassInfo(ObjectUtil.isNotEmpty(classInfo)?classInfo.toString():null);
                            if(ObjectUtil.isEmpty(table.getEnums())){
                                table.setEnums(new ArrayList<>());
                                table.setHasEnum("1");
                            }
                            if(ObjectUtil.isEmpty(column.getEnumHelpers())){
                                column.setEnumHelpers(new ArrayList<>());
                            }
                            table.getEnums().add(classNameStr);
                            for (int i=0;i<enumDatas.size();i++) {
                                JSONObject enumData = enumDatas.getJSONObject(i);
                                if(ObjectUtil.isNotEmpty(enumData)){
                                    column.getEnumHelpers().add(enumData.toJavaObject(EnumHelper.class));
                                }
                            }
                        }
                    }
                }
            }
        }

    }
    /**
     * 设置主键列信息
     *
     * @param table 业务表信息
     */
    public void setPkColumn(GenTable table)
    {
        for (GenTableColumn column : table.getColumns())
        {
            if (column.isPk())
            {
                table.setPkColumn(column);
                break;
            }
        }
        if (StringUtils.isNull(table.getPkColumn()))
        {
            table.setPkColumn(table.getColumns().get(0));
        }
        if (GenConstants.TPL_SUB.equals(table.getTplCategory()))
        {
            for (GenTableColumn column : table.getSubTable().getColumns())
            {
                if (column.isPk())
                {
                    table.getSubTable().setPkColumn(column);
                    break;
                }
            }
            if (StringUtils.isNull(table.getSubTable().getPkColumn()))
            {
                table.getSubTable().setPkColumn(table.getSubTable().getColumns().get(0));
            }
        }
    }
    /**
     * 导入表结构
     * @param tableList
     * @return
     */
    public void importGenTable(List<GenTable> tableList){
        try
        {
            for (GenTable table : tableList)
            {
                String tableName = table.getTableName();
                GenUtils.initTable(table);

                int row = baseMapper.insert(table);
                if (row > 0)
                {
                    // 保存列信息
                    List<GenTableColumn> genTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName);
                    for (GenTableColumn column : genTableColumns)
                    {
                        GenUtils.initColumnField(column, table);
                        genTableColumnMapper.insert(column);
                    }
                }
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
            throw new CustomException("导入失败：" + e.getMessage());
        }
    }


}
